package com.xpec.c4.persistence;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.HashMap;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * 持久化管理器
 * 
 * @author Magmaster
 *
 */
public class PersistenceManager
{
	/**
	 * Singleton 实例
	 */
	private static PersistenceManager instance = new PersistenceManager();
	
	/**
	 * 映射表：源对象 -> 持久化策略
	 */
	private HashMap<String, Strategy> mapSrcToStrategy;
	
	/**
	 * 映射表：Parser类名 -> Parser
	 */
	private HashMap<String, IParser> mapParser;
	
	/**
	 * 映射表：数据类名 -> Parser类名
	 */
	private HashMap<String, String> mapDataToParser;
			
	/**
	 * 映射表：Fly Weight 元件类名 -> Fly Weight Manager
	 */
	private HashMap<String, IFlyWeightManager> mapFwToManager;
	
	/**
	 * 获得Singleton实例的静态方法
	 * @return	singleton实例
	 */
	public static PersistenceManager getInstance()
	{
		return instance;
	}
	
	/**
	 * 私有构造方法，防止外部显式创建
	 */
	private PersistenceManager()
	{
		this.mapSrcToStrategy = new HashMap<String, Strategy>();
		this.mapParser = new HashMap<String, IParser>();
		this.mapDataToParser = new HashMap<String, String>();
		
		this.mapFwToManager = new HashMap<String, IFlyWeightManager>();
	}
	
	
	/**
	 * 获取给定类对应的策略
	 * @param srcClass		给定类名
	 * @return				对应策略
	 */
	public Strategy getStrategy(String srcClass)
	{
		return this.mapSrcToStrategy.get(srcClass);
	}
	
	
	/**
	 * 获取Parser
	 * @param strParser		Parser的类名
	 * @return				Parser对象
	 */
	public IParser getParser(String strParser)
	{
		return this.mapParser.get(strParser);
	}
	
	/**
	 * 加载持久化配置，包括Parser配置和Strategy配置
	 * @param	strPath		配置文件路径
	 */
	public void init(String strPath)
	{
		try
		{
			//加载Strategy
			DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			Document doc = docBuilder.parse(new java.io.File(strPath+"strategy_list.xml"));
			
			NodeList listStg = doc.getDocumentElement().getChildNodes();
			for(int i=0; i<listStg.getLength(); i++)
			{
				if(listStg.item(i).getNodeType() != Node.ELEMENT_NODE
						|| !listStg.item(i).getNodeName().equals("Strategy")) continue;
				
				Element eStg = (Element)listStg.item(i);
				
				Strategy stg = new Strategy();
				stg.target = eStg.getAttribute("target");
				stg.parser = eStg.getAttribute("parser");
				stg.isStrictOrder = "yes".equals(eStg.getAttribute("strict_order"));
					
				NodeList listProp = eStg.getChildNodes();
				for(int j=0; j<listProp.getLength(); j++)
				{
					if(listProp.item(j).getNodeType() != Node.ELEMENT_NODE
							|| !listProp.item(j).getNodeName().equals("Property")) continue;
						
						
					Element eProp = (Element)listProp.item(j);
					String propName = eProp.getAttribute("name");
					NamedNodeMap attrList = eProp.getAttributes();
					for(int k=0; k<attrList.getLength(); k++)
					{
						Node attr = attrList.item(k);
						stg.setFieldConfig(propName, attr.getNodeName(), attr.getNodeValue());
					}
				}
				
				this.mapSrcToStrategy.put(stg.target, stg);
			
			}
			
			//加载Parser
			doc = docBuilder.parse(new java.io.File(strPath+"parser_list.xml"));
			NodeList listParser = doc.getDocumentElement().getChildNodes();
			for(int i=0; i<listParser.getLength(); i++)
			{
				if(listParser.item(i).getNodeType() != Node.ELEMENT_NODE
						|| !listParser.item(i).getNodeName().equals("Parser")) continue;
				
				Element eParser = (Element)listParser.item(i);
				String strParser = (String)eParser.getAttribute("class");
				this.mapParser.put(strParser, (IParser)Class.forName(strParser).newInstance());
				
				NodeList listDataType = eParser.getChildNodes();
				for(int j=0; j<listDataType.getLength(); j++)
				{
					if(listDataType.item(j).getNodeType() != Node.ELEMENT_NODE
							|| !listDataType.item(j).getNodeName().equals("DataType")) continue;

					Element eData = (Element)listDataType.item(j);
					this.mapDataToParser.put(eData.getAttribute("class"), strParser);
				}
			}
			
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	
	/**
	 * 把给定对象转化成持久化数据
	 * @param src			待持久化对象
	 * @return				转化得到的持久化数据
	 */
	public Object build(Object src)
	{
		Strategy stg = this.mapSrcToStrategy.get(src.getClass().getName());
		if(stg == null) return null;
		else return this.mapParser.get(stg.parser).build(src, null);
	}
	
	/**
	 * 把给定的持久化数据转化成对象
	 * @param objToFillIn	待填充对象，如果不为null，则会将数据填充到objToFillIn中
	 * @param data
	 * @return		转化得到的对象
	 */
	public Object parse(Object objToFillIn, Object data)
	{
		IParser parser = null;
		Object [] keys = this.mapDataToParser.keySet().toArray();
		for(int i=0; i<keys.length; i++)
		{
			if(isInstanceOf(data.getClass(), (String)keys[i]))
			{
				parser = this.mapParser.get(this.mapDataToParser.get(keys[i]));
				break;
			}
		}
		if(parser == null) return null;
		else return parser.parse(objToFillIn, data, null);
	}
	
	/**
	 * 把给定的持久化数据转化成对象
	 * @param objToFillIn	待填充对象，如果不为null，则会将数据填充到objToFillIn中
	 * @param data
	 * @return		转化得到的对象
	 */
	public Object parse(Object data)
	{
		IParser parser = null;
		Object [] keys = this.mapDataToParser.keySet().toArray();
		for(int i=0; i<keys.length; i++)
		{
			if(isInstanceOf(data.getClass(), (String)keys[i]))
			{
				parser = this.mapParser.get(this.mapDataToParser.get(keys[i]));
				break;
			}
		}
		if(parser == null) return null;
		else return parser.parse(null, data, null);
	}
	
	/**
	 * 检查对象是否为给定类名的类的实例
	 * @param c				待检查对象的类对象
	 * @param className		对比类名
	 * @return				检查结果
	 */
	public static boolean isInstanceOf(Class<?> c, String className)
	{
		if(c == null) return false;
		else if(className.equals(c.getName())) return true;
		else
		{
			Class<?> [] interfaces = c.getInterfaces();
			Class<?> su = c.getSuperclass();
			
			boolean result = false;
			
			if(isInstanceOf(su, className)) result = true;
			else
			{
				for(int i=0; i<interfaces.length; i++)
				{
					if(isInstanceOf(interfaces[i], className))
					{
						result = true;
						break;
					}
				}
			}
			
			return result;
		}
	}
	
	/**
	 * 获得给定对象的属性，程序会递归的向上查找父类，直到找到给定名称的属性或到达继承树的根部
	 * @param c				类对象
	 * @param strField		属性名称
	 * @return				属性，如果未找到则返回 null
	 */
	public static Field getField(Class<?> c, String strField)
	{
		if(c == null) return null;
		
		try
		{
			return c.getDeclaredField(strField);
		}
		catch(NoSuchFieldException ex)
		{
			//ex.printStackTrace();
			
			return getField(c.getSuperclass(), strField);
		}
		catch(Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 根据给定的数组类型，返回数组成员的类型
	 * @param strArrayClass		数组类型，取值为：${ARRAY_OBJECT}.getClass().getName()
	 * @return					数组元素类型
	 */
	public static String getArrayElementClass(String strArrayClass)
	{
		String strElementClass = "";
		
		int [] iArray = new int[1];
		short [] shtArray = new short[1];
		long [] longArray = new long[1];
		boolean [] bArray = new boolean[1];
		float [] fArray = new float[1];
		double [] dbArray = new double[1];
		byte [] btArray = new byte[1];
		char [] chArray = new char[1];
		
		if(strArrayClass.equals(iArray.getClass().getName()))//int array
		{
			strElementClass = "int";
		}
		else if(strArrayClass.equals(shtArray.getClass().getName()))//short array
		{
			strElementClass = "short";
		}
		else if(strArrayClass.equals(longArray.getClass().getName()))//long array
		{
			strElementClass = "long";
		}
		else if(strArrayClass.equals(bArray.getClass().getName()))//boolean array
		{
			strElementClass = "boolean";
		}
		else if(strArrayClass.equals(fArray.getClass().getName()))//float array
		{
			strElementClass = "float";
		}
		else if(strArrayClass.equals(dbArray.getClass().getName()))//double array
		{
			strElementClass = "double";
		}
		else if(strArrayClass.equals(btArray.getClass().getName()))//byte array
		{
			strElementClass = "byte";
		}
		else if(strArrayClass.equals(chArray.getClass().getName()))//char array
		{
			strElementClass = "char";
		}
		else
		{
			strElementClass = strArrayClass.substring(strArrayClass.indexOf("L")+1);
			strElementClass = strElementClass.substring(0, strElementClass.length()-1);
		}
		
		return strElementClass;
	}
	
	/**
	 * 根据给定类型创建数组对象
	 * @param strClass		数组类型字符串，取值为：${ARRAY_OBJECT}.getClass().getName()
	 * @param length		数组的长度
	 * @return				新的数组对象
	 */
	public static Object createArrayObject(String strClass, int length)
	{
		Object objArray = null;
		
		int [] iArray = new int[1];
		short [] shtArray = new short[1];
		long [] longArray = new long[1];
		boolean [] bArray = new boolean[1];
		float [] fArray = new float[1];
		double [] dbArray = new double[1];
		byte [] btArray = new byte[1];
		char [] chArray = new char[1];
		
		if(strClass.equals(iArray.getClass().getName()))//int array
		{
			objArray = new int[length];
		}
		else if(strClass.equals(shtArray.getClass().getName()))//short array
		{
			objArray = new short[length];
		}
		else if(strClass.equals(longArray.getClass().getName()))//long array
		{
			objArray = new long[length];
		}
		else if(strClass.equals(bArray.getClass().getName()))//boolean array
		{
			objArray = new boolean[length];
		}
		else if(strClass.equals(fArray.getClass().getName()))//float array
		{
			objArray = new float[length];
		}
		else if(strClass.equals(dbArray.getClass().getName()))//double array
		{
			objArray = new double[length];
		}
		else if(strClass.equals(btArray.getClass().getName()))//byte array
		{
			objArray = new byte[length];
		}
		else if(strClass.equals(chArray.getClass().getName()))//char array
		{
			objArray = new char[length];
		}
		else
		{
			String result = strClass.substring(strClass.indexOf("L")+1);
			result = result.substring(0, result.length()-1);
			
			try
			{
				objArray = Array.newInstance(Class.forName(result), length);
			}
			catch (NegativeArraySizeException e)
			{
				e.printStackTrace();
			}
			catch (ClassNotFoundException e)
			{
				e.printStackTrace();
			}
		}
		
		
		return objArray;
	}


	/**
	 * 注册享元管理器
	 * @param type			享元管理器的类型，应该使用GameSystem定义的静态变量，通常为享元的类名
	 * @param manager		享元管理器
	 */
	public void registerFlyWeightManager(String type, IFlyWeightManager manager)
	{
		this.mapFwToManager.put(type, manager);
	}
	
	/**
	 * 返回指定类型的享元管理器
	 * @param type		注册类型，通常为享元的类名
	 * @return			如果注册类型的工厂不存在则返回null
	 */
	public IFlyWeightManager getFlyWeightManager(String type)
	{
		return this.mapFwToManager.get(type);
	}

}
